using System;

namespace PDUConverter
{
    /// <summary>
    /// Represents an incoming SMS PDU.
    /// </summary>
    public abstract class IncomingSmsPdu : SmsPdu
    {
        /// <summary>
        /// The flags for this message.
        /// </summary>
        protected IncomingMessageFlags _messageFlags;
        private const byte TP_MTI_SMS_Deliver = 0;
        private const byte TP_MTI_SMS_Status_Report = 2;
        private const byte TP_MTI_SMS_Submit_Report = 1;

        /// <summary>
        /// Decodes an incoming SMS PDU stream.
        /// </summary>
        /// <param name="pdu">The PDU string to decode.</param>
        /// <param name="includesSmscData">Specify true if the PDU data contains an SMSC header, otherwise false.</param>
        /// <returns>An IncomingSmsPdu object representing the decoded message.</returns>
        /// <remarks>Use this overload only if you do not know the size of the PDU data.</remarks>
        public static IncomingSmsPdu Decode(string pdu, bool includesSmscData)
        {
            return Decode(pdu, includesSmscData, -1);
        }

        /// <summary>
        /// Decodes an incoming SMS PDU stream.
        /// </summary>
        /// <param name="pdu">The PDU string to decode.</param>
        /// <param name="includesSmscData">Specify true if the PDU data contains an SMSC header, otherwise false.</param>
        /// <param name="actualLength">The size of the PDU data in bytes, not counting the SMSC header. Set to -1 if unknown.</param>
        /// <returns>An IncomingSmsPdu object representing the decoded message.</returns>
        public static IncomingSmsPdu Decode(string pdu, bool includesSmscData, int actualLength)
        {
            if (pdu == string.Empty)
            {
                throw new ArgumentException("pdu must not be an empty string.");
            }
            int num = 0;
            if (includesSmscData)
            {
                byte @byte = BcdWorker.GetByte(pdu, num++);
                if (@byte > 0)
                {
                    num += @byte;
                }
            }
            IncomingMessageType messageType = GetMessageType(BcdWorker.GetByte(pdu, num++));
            switch (messageType)
            {
                case IncomingMessageType.SmsDeliver:
                    return new SmsDeliverPdu(pdu, includesSmscData, actualLength);

                case IncomingMessageType.SmsStatusReport:
                    return new SmsStatusReportPdu(pdu, includesSmscData, actualLength);
            }
            throw new NotSupportedException("Message type " + messageType + " recognized, but not supported by the SMS decoder.");
        }

        private static IncomingMessageType GetMessageType(byte flags)
        {
            var num = (byte) (((((flags & 2) > 0) ? 1 : 0) * 2) + (flags & 1));
            switch (num)
            {
                case 0:
                    return IncomingMessageType.SmsDeliver;

                case 1:
                    return IncomingMessageType.SmsSubmitReport;

                case 2:
                    return IncomingMessageType.SmsStatusReport;
            }
            throw new ArgumentException("Unknown message type " + num + " (flags=" + flags + ")", "flags");
        }

        /// <summary>
        /// Gets the message type.
        /// </summary>
        public IncomingMessageType MessageType
        {
            get
            {
                return _messageFlags.MessageType;
            }
        }
    }
}